import java.io.*;   //output,input
import java.net.*;  //serversocket,socket
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;




public class Server {

	//Main method to create and start up server
	//startServer-->method to start up main THREAD

	public static int MIN = 0;
	public static int BANK = 0;
	public static String LastMove;
	public static ArrayList<Card> Deck;
	public static ArrayList<Card> Deck2;
	boolean Draw = false;
	
	public static void main(String args[]){
		int port = 5000;
		Server server = new Server(port,2,1500);  //(5000,2 graczy)
		server.startServer();
	}
	

//-----------------VariablesDeclaration---------------------------------//
	

	private ServerSocket echoServer;  	//deklaracja gniazdo serwera-echoServer
	private Socket clientSocket = null; //deklaracja gniazda po stronie serwera do lączenia 
	
	private int numConnections = 0;         //deklaracja liczby Połączeń
	private int port,Stack ;                 //port i liczba zetonów uzyty w konstruktorze 
	private boolean connecting = true;
	private boolean playing = false;
	
	
	private int Dealer,MC,DC,Turn;                 //current dealer used for current roun
	private static int PlayersLeft;   //changed made!!!
	//ArrayList<Card> Deck;
	//ArrayList<Card> Deck2;
	private Card card;
	private static int Stake;
	public static int ActiveLeft;
	public static int AllinCount;
	public static int PlayerStack;
	public static int Count;
	
	
	public static int members;                   //variable presenting how many players we want to join-used in constructor
	Thread TH[]; 				//array used to gather all players threads(static because used in static method)
	String S;
	public static int[] Moved;
	
//----------------------CONSTRUCTOR--------------------------------------//
	public Server(int x, int members, int Stack){
		this.port = x; 
		this.Stack = Stack;
		this.members = members;
		TH = new Thread[members];
		Moved = new int[members];
	}
	
//---------------------startServerClass----------------------------------//
	
	/*THis method of ServerClass is responsible for:
	 * -creating a server 
	 * -listening for other Players requesting for connection
	 * -starting a new Thread for each new Client(THREAD)==Player
	 */
	
	
	public void startServer() {
		
		PlayerConnected NewPlayer;   //declaration of Client_thread
		//P = new String[this.members];  //String messages responsibles for sending messages

		//Runnable interface - pointers to PlayerConnected method
		//new Thread(NewPlayer) - thread class for starting thread 
		
		try {
			echoServer = new ServerSocket(port); //Inicialization of server object with given port and backlog
		} catch (IOException e) {
			System.out.println("Error while trying to create Server: " + e);
		}
		
		//Server Created Succesfully//
		System.out.println("Server is started and is waiting for all players to join");
		System.out.println("Waiting for other players.....");
		
		
		while(connecting){   //Infinite loop for running server
			try {
				
				clientSocket = echoServer.accept();        //Creating new Socket for each new client
				numConnections = numConnections + 1;       //numbers of players from 1 to 6.
				NewPlayer = new PlayerConnected(clientSocket,numConnections,this); //new Thread start-each for new players,NewPlayer-obiekt impelmentujacy Runnable
				NewPlayer.start();								//Thread for New players start running
				System.out.println("Player" + numConnections + " connected to the server.");
				TH[numConnections-1] = NewPlayer;    //Array of threads being fullfiled	
				
				if(numConnections == this.members)
					connecting = false;
				 
				} catch (IOException e) {
				System.out.println("Unsuccessful Player attempt to connect!");}
				}
				
				
				((PlayerConnected) TH[0]).Dealer(); //Nie wiem czemu ale tak trzeba!,rzutowanie
				Dealer = 0;            //We establish who has following positions:Dealer,SmallBlind,BigBlind;
				PlayersLeft = numConnections;
				
				
//----------------------Preapering_Table-----------------------------//
				while(PlayersLeft > 1){	
				System.out.println("Preparing for establishin dealers,BB and SB!");
				MC=SB(Dealer,this.members);
				DC=BB(Dealer,this.members,MC);
				Turn = Turn(DC,this.members);
				BANK = ((PlayerConnected) TH[MC]).SmallBLind() + ((PlayerConnected) TH[DC]).BigBlind();
				Deck = Deck();     //Our playing Deck
				Deck2 = Deck();
				System.out.println("Deck created!");
				
				for(int i=0;i<=members-1;i++)             //Need to distribute cards
					if(TH[i].isAlive())  
						for(int j=0;j<4;j++){
							card = Distribution(Deck); 
							 ((PlayerConnected) TH[i]).TakeCards(j, card);}
						
				System.out.println("Distribution finished");	
				
				for(int i = 0;i<=members-1;i++)
					if(TH[i].isAlive())
						((PlayerConnected) TH[i]).SendHand();
				
				System.out.println("Cards send to the Players");	
				
			
				
				//Now its time to update player gui before we start auction.
				//we send basic info before auction-it is MC,DC,Dealer posistion and game bank
				for(int i=0;i<=members-1;i++)
					if(TH[i].isAlive())
						if(i != Turn)
							((PlayerConnected) TH[i]).SendBasicInfo(BANK,Dealer,MC,DC,Turn,9);
						else
							((PlayerConnected) TH[i]).SendBasicInfo(BANK,Dealer,MC,DC,Turn,10);
				
				S="C";
				for(int i=0;i<=5;i++) 
					if(i<=members-1)
						if(TH[i].isAlive())
							S=S+",A";
						else
							S=S+",D";
					else
						S=S+",D";
				
				//We sending message only to playing players!
				for(int i=0;i<=members-1;i++)
					if(TH[i].isAlive())
						((PlayerConnected) TH[i]).CleanUp(S);
				
				//-----------------Sending_Stack_And_Bank--------------------//				
				
				S="S";
				for(int i=0;i<=members-1;i++)
					if(TH[i].isAlive())
						S=S+","+((PlayerConnected) TH[i]).Stack();
				
				for(int i=0;i<=members-1;i++)
					if(TH[i].isAlive())
						((PlayerConnected) TH[i]).SendStack(S);
						
				S="C"; //!!!!!!!!!!
				
				

				S="";
				playing = true;					   //In first encounter,first player to join is becoming a dealer.
				MIN = 30;
				ActiveLeft = numConnections;
				int Rounds;
				int Moves;
				for(int i=0;i<=numConnections-1;i++)
					Moved[i] = 0;
				
				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
//---------------GameStarting----------------------------------//
		//while(PlayersLeft > 1){ //game is played  while Players != 1)-this mean that in game there is only one player left!
			
			Rounds = 1;
			Moves = 0;
			System.out.println("Round "+ Rounds + " started!");
			while( (Rounds<5 && ActiveLeft>1) ||  (AllinCount >0 && Rounds<5) ){
				System.out.println("CHUUUUUUUUUUUUUUj");
				while( (Moves != ActiveLeft && ActiveLeft>1) && (Moves < ActiveLeft && ActiveLeft>1) || (AllinCount > 0 && ActiveLeft>=1) ) 
				{   
					System.out.println("Moves count equal to: "+Moves);
					for(int i=0;i<=members-1;i++)
						if(TH[i].isAlive())
							if(i == Turn){
								System.out.println("Player of index "+ i +"was given a turn");
								((PlayerConnected) TH[i]).Turn(MIN,i);}
						
					
					System.out.println("Server waiting for player move");
					
					try {
						Thread.sleep(10000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
					System.out.println("Player Moved");
					System.out.println(Turn+","+LastMove+","+BANK+","+Stake);
					for(int i=0;i<=members-1;i++)
						if(TH[i].isAlive()){
							((PlayerConnected) TH[i]).MovedMade(Turn, LastMove, BANK, Stake,PlayerStack);
							((PlayerConnected) TH[i]).UpdateStack();}
					
					System.out.println("GUI UPDATED");
					if(AllinCount <= ActiveLeft)
						Turn = NewTurn(Turn,this.members);
					
					for(int i =0;i<=this.members-1;i++)
						if(TH[i].isAlive())
							if(Moved[i] == 1 && ((PlayerConnected) TH[i]).IsActive() )
								Moves=Moves+1;
					
					for(int i =0; i<=this.members-1;i++)
						 if(Moved[i] == 0 && ((PlayerConnected) TH[i]).IsActive())
							Moves = Moves -1;
					System.out.println("Min stack wynosi teraz: "+ MIN);
					System.out.println("Liczba akrywnych graczy: " + ActiveLeft);
				}
				//if(Rounds != 4)
				System.out.println("All players made move. Its time to exchange cards");
				System.out.println("Round "+Rounds+" Finished!");
				//All Moves were make, its time for a new Round.(exchange of cards,and prepeare for new auction)
				Moves = 0;
				Rounds = Rounds +1;
				if(Rounds -1 != 4){
				for(int i=0;i<=numConnections-1;i++)
					Moved[i] = 0;
				
				for(int i =0;i<=this.members-1;i++)
					if(TH[i].isAlive())
						if( ( (PlayerConnected) TH[i]).IsActive() || ((PlayerConnected) TH[i]).IsALLIN() )
						{	
							((PlayerConnected) TH[i]).Clear();
							((PlayerConnected) TH[i]).DiscardCards();
							((PlayerConnected) TH[i]).E();}
			
				System.out.println("Ask sent");
				try {
					Thread.sleep(10000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				System.out.println("EXCHANGES WERE MADE");}
				MIN = 0;
				
				if(AllinCount <= ActiveLeft)
					Turn = NewTurn(SB(Dealer,this.members),this.members);
				
				for(int i =0;i<=this.members-1;i++)
					if(TH[i].isAlive())
						((PlayerConnected) TH[i]).RoundStake();
						
				
			
			}
		
			System.out.println("Comparing Rankings!");
			for(int i=0;i<=this.members-1;i++)		
				if(TH[i].isAlive())
					if( ( (PlayerConnected) TH[i]).IsActive() || ((PlayerConnected) TH[i]).IsALLIN() )
						((PlayerConnected) TH[i]).InitiateRank(i);
		
			System.out.println("Comparing Rankings!");
	
			int z = 0;
			int DrawCount = 0;
			int[] B = new int[this.members];
			for(int i=0;i<=this.members-1;i++)		
				if(TH[i].isAlive())
					if( ( (PlayerConnected) TH[i]).IsActive() || ((PlayerConnected) TH[i]).IsALLIN() )
						B[i]=1;
					else
						B[i]=0;
			
			for(int i=0;i<=this.members-1;i++)	
				if(B[i]==1)
					for(int j=i+1;j<=this.members-1;j++)	
						if(B[j]==1){
							z=Comparison(((PlayerConnected) TH[i]).CardRank,((PlayerConnected) TH[j]).CardRank);
							if(z==1)
								B[j]=0;
							else if(z==2){
								B[i]=0;
								i=j;
								j=10;
								Draw=false;}
							else{
								B[j]=0;
								Draw = true;}
						}		
						
			System.out.println("Comparing finished");
			//Place for implementing new dealer,MC,DC,Rankin
			if(Draw==true)
				System.out.println("We have a draw!. The whole Bank is taken by a Server!");
			else
				for(int i =0;i<=B.length-1;i++)
					if(B[i]==1){
						System.out.println("Player"+(i+1)+" have won!");
						((PlayerConnected) TH[i]).Won(BANK);}
			
			//Bot,checkstyle,clear of data,preapre for new round!
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			
			BANK = 0;
			MIN = 30;
			LastMove = "";
			PlayerStack = 0;
			Stake = 0;
			//we need to loop to check kill quest who habe 0 stack
			for(int i=0;i<=this.members-1;i++)
				if(TH[i].isAlive()){
					((PlayerConnected) TH[i]).Check();}
			
			for(int i=0;i<=this.members-1;i++)
				if(TH[i].isAlive()){
					((PlayerConnected) TH[i]).RC();}
			
			}
				
			System.out.println("Game Finished!");
			/*
			for(int i=0;i<=this.members-1;i++)
				if(TH[i].isAlive())
					System.out.println("Game was won by Player: "+(i+1)); */
			
			
			
			try {
				clientSocket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			
			connecting=false;
		
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	//---------------------CLASS-METHODS----------------------//
	
	//Updating Bank and minimum stake after each player turn
	public static void BankUpdate(int X,int Y,int M,String S,int PS){
		BANK = BANK + Y;
		MIN = M;
		LastMove = S;
		PlayerStack = PS;
		Stake = X;
	}
	
	public static void Left(){
		PlayersLeft = PlayersLeft - 1;
	}
	
	
	
	public int NewTurn(int turn,int memb) {
		int i;
		if(turn == memb-1)
		     i=0;
		else
			i=turn+1;
			
		
		
		while(true){
			if(TH[i].isAlive())
				if(((PlayerConnected) TH[i]).Active)
					return i;
			else
				if(i < memb-1)
					i++;
				else
					i=0;
	
	}
		
	}

	//---------------------------CLassMethod_To_Find_Dealer-----------------------//
	public int DealerCheck(){
		boolean DealerFound = false;
		int i = 0;
		while(!DealerFound){
			if(TH[i].isAlive())
				if(((PlayerConnected) TH[i]).IsDealer())
					DealerFound = true;
		i=i+1;
		}
		i=i-1;
		return i;
	}
	
//----------------Method_to_define_BigBlind----------------//	
	public int BB(int dealer,int PL,int MC){
		int i;
		if(MC==PL-1)
			i=0;
		else
			i=MC+1;
		
		
				while(true){
					if(TH[i].isAlive())
						return i;
					else
						if(i < PL-1)
							i++;
						else
							i=0;
			
			}
	}
//-----------------Method_to_determine_SmallBlind----------------------//
public int SB(int dealer,int memb){   
	int i;
	if(dealer==memb-1)
		i=0;
	else
		i=dealer+1;
	
	while(true){
		if(TH[i].isAlive())
			return i;
		else{
			if(i < memb-1)
				i++;
			else
				i=0;}
	}
}

public int Turn(int DC,int memb){
	
	int i;
	if(DC==memb-1)
		i=0;
	else
		i=DC+1;

	
	while(true){
		if(TH[i].isAlive())
			return i;
		else{
			if(i < memb)
				i++;
			else
				i=0;}
	}
}


//--------------MethodToCreate_Deck--------------//
public static ArrayList<Card> Deck(){
	ArrayList<Card> Deck = new ArrayList<Card>(); //we create ArrayList of Cards
	Card card;
	
	for(int i=0;i<=3;i++)                       //we create all cards by 4 colours
		for(int j = 1;j<=13;j++){
			card = new Card(i,j);
			Deck.add(card);
			
		}
	
	return Deck;
}


	
//----------------Shuffle-Method-------------------//


public static ArrayList<Card> Shuffle(ArrayList <Card> D){
	Collections.shuffle(D);
	return D;         
	
}


//--------------Distribution--------------------//

public static Card Distribution(ArrayList<Card> D){
	Card c; //card which will be given to player
	Random rnd = new Random();
	int x;

			x = rnd.nextInt(D.size());
			c = D.get(x);
			D.remove(x);
	
	return c;
		
	
}  

public int Comparison(Rank R1,Rank R2){
	
	if(R1.CardNumbers>R2.CardNumbers)
		return 1;
	else if (R1.CardNumbers<R2.CardNumbers)
		return 2;
	else
		for(int i=0;i<=R2.POM2.size()-1;i++)
			if(R2.POM2.get(i)>R1.POM2.get(i))
				return 1;
			else if (R1.POM2.get(i)>R2.POM2.get(i))
				return 2;
	
	return 0;
					
	
}		
	
	
}
